package com.PVZ.engine;

import com.PVZ.engine.map.GameMap;
import com.PVZ.engine.map.MapBlock;
import com.PVZ.event.*;
import com.PVZ.model.Entity;
import com.PVZ.model.bullet.Bullet;
import com.PVZ.model.bullet.Sun;
import com.PVZ.model.emuns.AnimeType;
import com.PVZ.model.emuns.MoveType;
import com.PVZ.model.emuns.PlantType;
import com.PVZ.model.interfaces.EventSource;
import com.PVZ.model.interfaces.Gettable;
import com.PVZ.model.plant.Plant;
import com.PVZ.model.weapon.Bomb;
import com.PVZ.model.weapon.Weapon;
import com.PVZ.model.zombie.PaperZombie;
import com.PVZ.model.zombie.Zombie;
import com.PVZ.utils.Util;
import com.PVZ.view.CardView;
import lombok.Getter;
import lombok.Setter;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by @Author: kabuda on @Date: 2021/5/20 11:31
 * <p>
 * 判断器 用于判断所有对象的状态(击中 死亡 等)
 */
@Getter
@Setter
public class Judgement extends EventSource {
    private Stage stage;
    private Cleaner cleaner;
    private CardView cardView;
    private int sun = 0;

    public Judgement(Stage stage, Cleaner cleaner, CardView cardView) {
        this.stage = stage;
        this.cleaner = cleaner;
        this.cardView = cardView;
        this.bindListener(new AttackEventListener(stage));
        this.bindListener(new ClickGettableListener());
        this.bindListener(new DeadEventListener());
    }

    public void gameOverJudge(){
        if(stage.getIsOver()){
            if(stage.getLevel().getLevelTime()<200){
                JOptionPane.showMessageDialog(null, "你输了", "游戏结束", JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            }else{
                JOptionPane.showMessageDialog(null, "你赢了", "游戏结束", JOptionPane.WARNING_MESSAGE);
                System.exit(0);
            }
        }
    }


    public void sunJudge() {
        if (Stage.sunQuantity != sun) {
            cardView.repaintToolBar();
            this.sun = Stage.sunQuantity;
        }
    }

    /**
     * 进行实体类的有关判断 如是否需要清除 是否死亡 是否攻击等
     */
    public void entityJudge() {
        //更新单元格内的内容及清理不需要的类
        List<Entity> allEntityList = stage.getAllEntityList();

        //清理单元格
        this.stage.getLevel().getGameMap().clearBlocks();

        sunJudge();
        //清理类
        for (int i = 0; i < allEntityList.size(); i++) {
            Entity entity = allEntityList.get(i);

            deadJudge(entity);
            changeForm(entity);
            updateEntity(entity);
            gameOverJudge();
        }
    }

    public void updateEntity(Entity entity) {
        cleaner.updateEntityFromStage(entity, stage);
        if (entity.getPoint() != null) {
            //将entity放入单元格
            MapBlock block = Util.getBlockByPoint(entity.getPoint());
            if (block != null) {
                block.addEntity(entity);
            }
        }
    }

    public void deadJudge(Entity entity) {

        this.notifyListener(new DeadEvent(entity));
    }

    /**
     * @param entity 转化形态
     */
    public void changeForm(Entity entity) {

        if (entity instanceof Zombie) {
            if (!((Zombie) entity).getIsTransformed()) {
                if (entity.health > 0 && entity.health <= entity.getTransformZombies()) {
                    Util.changeAnime(entity, AnimeType.MOVE);
                    Util.changeAnime(entity, AnimeType.ATTACK);
                    if (entity instanceof PaperZombie) {
                        entity.setCurSpeed(3);
                    }
                    ((Zombie) entity).setIsTransformed(true);
                }
            }

        }
    }

    /**
     * 测试 单元格点击事件判定
     *
     * @return 被点击的单元格
     */
    public MapBlock clickJudge(Point point) {
        //遍历单元格
        return Util.getBlockByPoint(point);
    }

    /**
     * 攻击判定
     */
    public void attackJudge() {
        MapBlock[][] blocks = GameMap.blocks;

        //遍历单元格
        for (MapBlock[] mapBlocks : blocks) {
            for (MapBlock block : mapBlocks) {

                List<Plant> plants = block.getPlants();
                if (block.isHasPlant()) {
                    //植物攻击的判断
                    for (Plant plant : plants) {

                        Weapon weapon = plant.getWeapon();
                        if (weapon != null) {
                            int row = plant.getRow();
                            int col = plant.getCol();

                            if (weapon instanceof Bomb) {

                                for (int i = row - 1; i <= row + 1; i++) {
                                    for (int j = col - 1; j <= col + 1; j++) {
                                        MapBlock blockByCoor = Util.getBlockByCoor(i, j);
                                        if (blockByCoor != null) {
                                            for (Zombie zombie : blockByCoor.getZombies()) {
                                                if (weapon.getIsBoobed()) {
                                                    zombie.boomed();
                                                    Point point = plant.getPoint();
                                                    Util.getBlockByPoint(point).setHasPlant(false);
                                                }
                                            }
                                        }
                                    }
                                }
                                weapon.setIsBoobed(false);
                            } else {
                                for (int j = col; j <= col + weapon.getAttackFiled(); j++) {
                                    //寻找攻击范围内有没有僵尸
                                    MapBlock tempBlock = Util.getBlockByCoor(row, j);

                                    if (tempBlock == null) {
                                        break;
                                    }
                                    if (tempBlock.hasZombie()) {
                                        this.notifyListener(new AttackEvent(plant));
                                        break;
                                    }
                                }
                            }

                        }

                    }


                }

                if (block.hasBothZombieAndPlant()) {
                    //僵尸攻击
                    List<Entity> enemies = new ArrayList<>();

                    //具体判断是否可以攻击 产生攻击事件，停止移动。。。
                    // 僵尸和植物都会产生攻击事件，攻击单元格中列表的第一个就好了，如果是范围伤害（土豆雷）则 整个列表都会受到伤害
                    //先遍历当前单元格中的僵尸  !!需要改进，因为还有植物，障碍等多种实体
                    for (Zombie zombie : block.getZombies()) {
                        if (zombie.getIsAlive() == Zombie.ALIVE) {
                            //活着才会攻击
                            if (zombie.getWeapon().getCurCoolTime() == 0) {
                                //冷却好了才能攻击
                                for (Plant plant : plants) {
                                    //注意要算碰撞箱体积
                                    int attackField = zombie.getBoxRightPositionX() - zombie.getWeapon().getAttackFiled();

                                    //僵尸从右向左触碰到植物右边的碰撞箱
                                    if (attackField <= plant.getBoxRightPositionX() && plant.getPlantType() != PlantType.Spikeweed && plant.getPlantType() != PlantType.CherryBomb) {
                                        if (!enemies.contains(plant)) {
                                            enemies.add(plant);
                                        }
                                        //跳跳僵尸未判断
                                    }
                                }
                            }
                            if (enemies.size() != 0) {
                                //将攻击交给AttackListener
                                AttackEvent attackEvent = new AttackEvent(zombie, enemies);
                                //通知事件处理器处理事件
                                this.notifyListener(attackEvent);
                            }
                        }
                    }
                }

                if (block.hasBothZombieAndBullet()) {
                    //单元格内同时有子弹和僵尸
                    List<Bullet> bullets = block.getBullets();

                    Zombie zombie = block.getZombies().get(0);


                    for (int i = 0; i < bullets.size(); i++) {
                        Bullet bullet = bullets.get(i);
                        if (bullet == null) {
                            break;
                        }
                        bullet.setMoveType(MoveType.Stop);

                        bullet.setHealth(-1);
                        bullet.setCurAnimeType(AnimeType.BREAK);
                        bullet.setIsAlive(Entity.DEAD);

                        zombie.setHealth(zombie.getHealth() - bullet.getDamage());
                    }
                }
            }
        }
    }


    /**
     * 处理拾取操作
     *
     * @param point 点击坐标
     * @param block 单元格
     */
    public void clickGetJudge(Point point, MapBlock block) {
        List<Gettable> gettableList = block.getGettableList();


        for (int i = 0; i < gettableList.size(); i++) {
            Gettable gettable = gettableList.get(i);
            //阳光的处理
            if (gettable instanceof Sun) {
                Sun sun = (Sun) gettable;
                Stage.sunQuantity += 50;

                int boxLeftPositionX = sun.getBoxLeftPositionX();
                int boxRightPositionX = sun.getBoxRightPositionX();
                int boxUpPositionY = sun.getBoxUpPositionY();
                int boxDownPositionY = sun.getBoxDownPositionY();
                if (point.getX() >= boxLeftPositionX + 10 && point.getX() <= boxRightPositionX + 40 && point.getY() >= boxUpPositionY - 10 && point.getY() <= boxDownPositionY + 30) {
                    //太阳移动到 381，36 图标位置 无论在什么位置都20次移动完毕
                    this.notifyListener(new ClickGettableEvent(sun));
                }

                gettableList.remove(gettable);
            }
        }

    }

}
